package com.crrepa.sdk.sample.device;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.crrepa.ble.CRPBleClient;
import com.crrepa.ble.conn.CRPBleConnection;
import com.crrepa.ble.conn.CRPBleDevice;
import com.crrepa.ble.conn.bean.CRPActionDetailsInfo;
import com.crrepa.ble.conn.bean.CRPActivityReminderInfo;
import com.crrepa.ble.conn.bean.CRPDailyGoalsInfo;
import com.crrepa.ble.conn.bean.CRPDailyTrainingInfo;
import com.crrepa.ble.conn.bean.CRPFirmwareVersionInfo;
import com.crrepa.ble.conn.bean.CRPHeartRateInfo;
import com.crrepa.ble.conn.bean.CRPHistoryBloodOxygenInfo;
import com.crrepa.ble.conn.bean.CRPHistoryHeartRateInfo;
import com.crrepa.ble.conn.bean.CRPHistoryHrvInfo;
import com.crrepa.ble.conn.bean.CRPHistoryStressInfo;
import com.crrepa.ble.conn.bean.CRPHistoryTempInfo;
import com.crrepa.ble.conn.bean.CRPHistoryTrainingInfo;
import com.crrepa.ble.conn.bean.CRPSettingInfo;
import com.crrepa.ble.conn.bean.CRPSleepChronotypeInfo;
import com.crrepa.ble.conn.bean.CRPSleepDetailsInfo;
import com.crrepa.ble.conn.bean.CRPSleepInfo;
import com.crrepa.ble.conn.bean.CRPStepsDetailsInfo;
import com.crrepa.ble.conn.bean.CRPStepsInfo;
import com.crrepa.ble.conn.bean.CRPTimingBloodOxygenInfo;
import com.crrepa.ble.conn.bean.CRPTimingHrvInfo;
import com.crrepa.ble.conn.bean.CRPTimingStressInfo;
import com.crrepa.ble.conn.bean.CRPTrainingDayGoalsInfo;
import com.crrepa.ble.conn.bean.CRPTrainingGoalsInfo;
import com.crrepa.ble.conn.bean.CRPTrainingInfo;
import com.crrepa.ble.conn.bean.CRPUserInfo;
import com.crrepa.ble.conn.bean.CRPVoltageInfo;
import com.crrepa.ble.conn.callback.CRPFirmwareHashCallback;
import com.crrepa.ble.conn.callback.CRPFirmwareVersionCallback;
import com.crrepa.ble.conn.callback.CRPHeartRateAlertCallback;
import com.crrepa.ble.conn.callback.CRPMessageCallback;
import com.crrepa.ble.conn.callback.CRPNewFirmwareVersionCallback;
import com.crrepa.ble.conn.callback.CRPRFPowerCallback;
import com.crrepa.ble.conn.callback.CRPReadBookModeCallback;
import com.crrepa.ble.conn.callback.CRPRemoteControlStateCallback;
import com.crrepa.ble.conn.callback.CRPSettingCallback;
import com.crrepa.ble.conn.callback.CRPShutDownCallback;
import com.crrepa.ble.conn.callback.CRPSosStateCallback;
import com.crrepa.ble.conn.listener.CRPActionDetailsListener;
import com.crrepa.ble.conn.listener.CRPActivityReminderListener;
import com.crrepa.ble.conn.listener.CRPBatteryListener;
import com.crrepa.ble.conn.listener.CRPBleConnectionStateListener;
import com.crrepa.ble.conn.listener.CRPBloodOxygenChangeListener;
import com.crrepa.ble.conn.listener.CRPBloodPressureChangeListener;
import com.crrepa.ble.conn.listener.CRPDeviceVoltageListener;
import com.crrepa.ble.conn.listener.CRPDisplayListener;
import com.crrepa.ble.conn.listener.CRPGoalsListener;
import com.crrepa.ble.conn.listener.CRPHeartRateChangeListener;
import com.crrepa.ble.conn.listener.CRPHrvChangeListener;
import com.crrepa.ble.conn.listener.CRPOtaListener;
import com.crrepa.ble.conn.listener.CRPRemoteControlDetailsListener;
import com.crrepa.ble.conn.listener.CRPShutterListener;
import com.crrepa.ble.conn.listener.CRPSleepChangeListener;
import com.crrepa.ble.conn.listener.CRPStepsChangeListener;
import com.crrepa.ble.conn.listener.CRPStressChangeListener;
import com.crrepa.ble.conn.listener.CRPTempChangeListener;
import com.crrepa.ble.conn.listener.CRPTrainingChangeListener;
import com.crrepa.ble.conn.type.CRPBleMessageType;
import com.crrepa.ble.conn.type.CRPDisplayFeature;
import com.crrepa.ble.conn.type.CRPFirmwareCheckType;
import com.crrepa.ble.conn.type.CRPGoalsType;
import com.crrepa.ble.conn.type.CRPHistoryDay;
import com.crrepa.ble.conn.type.CRPOtaMcu;
import com.crrepa.ble.conn.type.CRPRFPower;
import com.crrepa.ble.conn.type.CRPReadBookMode;
import com.crrepa.ble.conn.type.CRPRemoteControlType;
import com.crrepa.ble.conn.type.CRPTrainingState;
import com.crrepa.ble.conn.type.CRPTempType;
import com.crrepa.ble.conn.type.CRPBloodOxygenType;
import com.crrepa.sdk.sample.R;
import com.crrepa.sdk.sample.SampleApplication;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * Created by bill on 2017/5/15.
 */

public class DeviceActivity extends AppCompatActivity {
    private static final String TAG = "DeviceActivity";
    public static final String DEVICE_ADDRESS = "address";

    ProgressDialog progressDialog;
    CRPBleClient bleClient;
    CRPBleDevice bleDevice;
    CRPBleConnection bleConnection;
    boolean isUpgrade = false;

    @BindView(R.id.tv_connect_state)
    TextView tvConnectState;
    @BindView(R.id.tv_firmware_version)
    TextView tvFirmwareVersion;
    @BindView(R.id.tv_battery)
    TextView tvBattery;
    @BindView(R.id.tv_step)
    TextView tvStep;
    @BindView(R.id.tv_distance)
    TextView tvDistance;
    @BindView(R.id.tv_calorie)
    TextView tvCalorie;
    @BindView(R.id.tv_restful)
    TextView tvRestful;
    @BindView(R.id.tv_light)
    TextView tvLight;
    @BindView(R.id.tv_heart_rate)
    TextView tvHeartRate;
    @BindView(R.id.tv_blood_pressure)
    TextView tvBloodPressure;
    @BindView(R.id.tv_upgrade_state)
    TextView tvUpgradeState;
    @BindView(R.id.btn_ble_connect_state)
    Button btnBleDisconnect;
    @BindView(R.id.tv_blood_oxygen)
    TextView tvBloodOxygen;
    @BindView(R.id.tv_new_firmware_version)
    TextView tvNewFirmwareVersion;

    private String firmwareVersion;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_device);
        ButterKnife.bind(this);
        initView();
        progressDialog = new ProgressDialog(this);
        String address = getIntent().getStringExtra(DEVICE_ADDRESS);
        if (TextUtils.isEmpty(address)) {
            finish();
            return;
        }

        bleClient = SampleApplication.getBleClient(this);
        bleDevice = bleClient.getBleDevice(address);
        if (bleDevice != null && !bleDevice.isConnected()) {
            connect();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (bleDevice != null) {
            bleDevice.disconnect();
        }
    }

    void initView() {
        updateStepInfo(0, 0, 0);
        updateSleepInfo(0, 0);
    }

    void connect() {
        progressDialog.show();
        bleConnection = bleDevice.connect();
        bleConnection.setConnectionStateListener(new CRPBleConnectionStateListener() {
            @Override
            public void onConnectionStateChange(int newState) {
                Log.d(TAG, "onConnectionStateChange: " + newState);
                int state = -1;
                switch (newState) {
                    case CRPBleConnectionStateListener.STATE_CONNECTED:
                        state = R.string.state_connected;
                        progressDialog.dismiss();
                        updateTextView(btnBleDisconnect, getString(R.string.disconnect));
                        testSet();
                        break;
                    case CRPBleConnectionStateListener.STATE_CONNECTING:
                        state = R.string.state_connecting;
                        break;
                    case CRPBleConnectionStateListener.STATE_DISCONNECTED:
                        closeGatt();
                        state = R.string.state_disconnected;
                        progressDialog.dismiss();
                        updateTextView(btnBleDisconnect, getString(R.string.connect));
                        break;
                }
                updateConnectState(state);
            }
        });

        bleConnection.setStepsChangeListener(stepsChangeListener);
        bleConnection.setSleepChangeListener(sleepChangeListener);
        bleConnection.setHeartRateChangeListener(heartRateChangeListener);
        bleConnection.setBloodOxygenChangeListener(bloodOxygenChangeListener);
        bleConnection.setBloodPressureListener(bloodPressureChangeListener);
        bleConnection.setHrvChangeListener(hrvChangeListener);
        bleConnection.setTempChangeListener(tempChangeListener);
        bleConnection.setStressChangeListener(stressChangeListener);
        bleConnection.setTrainingListener(trainingChangeListener);
        bleConnection.setActionDetailsListener(actionDetailsListener);
        bleConnection.setGoalsListener(goalsListener);
        bleConnection.setActivityReminderListener(activityReminderListener);
        bleConnection.setVoltageListener(voltageListener);
        bleConnection.setDisplayListener(displayListener);

    }

    private void closeGatt() {
        if (bleConnection != null) {
            bleConnection.close();
        }
    }

    private void testSet() {
        Log.d(TAG, "设备连接成功，开始获取所有数据");

        if (bleConnection != null) {
            // 1. 获取活动步数数据
            Log.d(TAG, "正在获取活动步数数据...");
            bleConnection.queryCurrentSteps(); // 获取当前步数
            bleConnection.queryHistorySteps(CRPHistoryDay.TODAY); // 获取今日步数历史
            bleConnection.queryHistoryStepsDetails(CRPHistoryDay.TODAY); // 获取今日步数详情
            
            // 2. 获取心率数据
            Log.d(TAG, "正在获取心率数据...");
            bleConnection.queryHistoryHeartRate(); // 获取历史心率数据
            bleConnection.enableTimingHeartRate(15); // 开启定时心率监测（15分钟间隔）
            bleConnection.queryTimingHeartRateState(); // 查询定时心率状态
            bleConnection.queryHistoryTimingHeartRate(CRPHistoryDay.TODAY); // 获取今日定时心率数据
            
            // 3. 获取心率变异性(HRV)数据
            Log.d(TAG, "正在获取心率变异性数据...");
            bleConnection.queryHistoryHrv(); // 获取历史HRV数据
            bleConnection.enableTimingHrv(15); // 开启定时HRV监测（15分钟间隔）
            bleConnection.queryTimingHrvState(); // 查询定时HRV状态
            bleConnection.queryHistoryTimingHrv(CRPHistoryDay.TODAY); // 获取今日定时HRV数据
            
            // 4. 获取压力数据
            Log.d(TAG, "正在获取压力数据...");
            bleConnection.queryHistoryStress(); // 获取历史压力数据
            bleConnection.enableTimingStress(15); // 开启定时压力监测（15分钟间隔）
            bleConnection.queryTimingStressState(); // 查询定时压力状态
            bleConnection.queryHistoryTimingStress(CRPHistoryDay.TODAY); // 获取今日定时压力数据
            
            // 5. 获取锻炼记录数据
            Log.d(TAG, "正在获取锻炼记录数据...");
            bleConnection.queryHistoryTraining(); // 获取历史训练数据
            bleConnection.queryHistoryDailyTraining(CRPHistoryDay.TODAY); // 获取今日训练数据
            bleConnection.querySupportTraining(); // 获取支持的训练类型
            bleConnection.queryTrainingState(); // 获取训练状态
            
            // 6. 获取睡眠数据
            Log.d(TAG, "正在获取睡眠数据...");
            bleConnection.queryHistorySleep(CRPHistoryDay.TODAY); // 获取今日睡眠数据
            bleConnection.queryHistorySleepList(); // 获取睡眠历史列表
            bleConnection.querySleepChronotype(); // 获取睡眠时型
            
            // 7. 获取血氧数据（补充健康数据）
            Log.d(TAG, "正在获取血氧数据...");
            bleConnection.queryHistoryBloodOxygen(); // 获取历史血氧数据
            bleConnection.enableTimingBloodOxygen(4); // 开启定时血氧监测（4小时间隔）
            bleConnection.queryTimingBloodOxygenState(); // 查询定时血氧状态
            bleConnection.queryHistoryTimingBloodOxygen(CRPHistoryDay.TODAY); // 获取今日定时血氧数据
            
            // 获取设备信息
            Log.d(TAG, "正在获取设备信息...");
            bleConnection.queryBattery(); // 获取电池信息
            bleConnection.queryFirmwareVersion(new CRPFirmwareVersionCallback() {
                @Override
                public void onVersion(String version) {
                    Log.d(TAG, "固件版本: " + version);
                    firmwareVersion = version;
                    updateTextView(tvFirmwareVersion, version);
                }
            });
            
            // 获取设置信息
            bleConnection.querySettingInfo(new CRPSettingCallback() {
                @Override
                public void onSetting(CRPSettingInfo info) {
                    Log.d(TAG, "设备设置信息: " + info);
                }
            });
            
            // 获取活动详情数据
            bleConnection.queryActionDetails(CRPHistoryDay.TODAY);
            
            Log.d(TAG, "所有数据获取请求已发送，等待设备响应...");
        }
    }


    @OnClick(R.id.btn_ble_connect_state)
    public void onConnectStateClick() {
        if (bleDevice.isConnected()) {
            bleDevice.disconnect();
        } else {
            connect();
        }
    }


    @OnClick({R.id.btn_query_firmware, R.id.btn_query_battery, R.id.btn_sync_time,
            R.id.btn_send_user_info, R.id.btn_sync_step,
            R.id.btn_sync_sleep, R.id.btn_query_history_sleep_list, R.id.btn_query_sleep_info,
            R.id.btn_query_sleep_details, R.id.btn_query_sleep_chronotype, R.id.btn_end_sleep,
            R.id.btn_start_training,
            R.id.btn_query_training_state, R.id.btn_send_goals, R.id.btn_query_goals,
            R.id.btn_query_support_message_list, R.id.btn_send_message, R.id.btn_send_training_state,
            R.id.btn_query_remote_control_details,
            R.id.btn_query_remote_control_state, R.id.btn_send_device_language,
            R.id.btn_send_binding_reminder,
            R.id.btn_send_activity_reminder, R.id.btn_query_activity_reminder,
            R.id.btn_start_measure_heart_rate, R.id.btn_stop_measure_heart_rate,
            R.id.btn_query_history_hreat_rate, R.id.btn_query_setting_info,
            R.id.btn_start_measure_blood_pressure, R.id.btn_stop_measure_blood_pressure,
            R.id.btn_sync_history_step, R.id.btn_sync_history_sleep,
            R.id.btn_firmware_upgrade, R.id.btn_send_screen_resolution, R.id.btn_query_history_voltage,
            R.id.btn_enable_timing_heart_rate, R.id.btn_disable_timing_heart_rate,
            R.id.btn_query_timing_hreat_rate,
            R.id.btn_start_measure_blood_oxygen, R.id.btn_stop_measure_blood_oxygen,
            R.id.btn_send_heart_rate_alert, R.id.btn_query_heart_rate_alert,
            R.id.btn_query_support_training_list, R.id.btn_query_history_training,
            R.id.btn_enable_shutter,
            R.id.btn_query_shutter_state,
            R.id.btn_send_rfpower, R.id.btn_query_rfpower,
            R.id.btn_check_firmware, R.id.shutdown,
            R.id.btn_restart, R.id.reset,
            R.id.btn_send_read_book_mode,
            R.id.btn_query_read_book_mode, R.id.btn_query_action_details,
            R.id.btn_enable_timing_hrv, R.id.btn_disable_timing_hrv,
            R.id.btn_start_measure_hrv, R.id.btn_stop_measure_hrv,
            R.id.btn_query_hrv_measure_result, R.id.btn_enable_timing_blood_oxygen,
            R.id.btn_disable_timing_blood_oxygen,
            R.id.btn_query_continue_blood_oxygen, R.id.btn_enable_timing_temp,
            R.id.btn_disable_timing_temp, R.id.btn_query_timing_temp_state,
            R.id.btn_query_timing_temp, R.id.btn_start_measure_stress,
            R.id.btn_stop_measure_stress, R.id.btn_query_history_stress,
            R.id.btn_enable_sos, R.id.btn_query_sos_state,
            R.id.btn_send_auto_lock, R.id.btn_query_auto_lock,
            R.id.btn_send_brightness, R.id.btn_send_display_feature, R.id.btn_query_display_feature,
            R.id.btn_query_brightness, R.id.btn_query_support_display_feature, R.id.btn_query_exercise_details})
    public void onViewClicked(View view) {
        if (!bleDevice.isConnected()) {
            return;
        }
        switch (view.getId()) {
            case R.id.btn_query_read_book_mode:
                bleConnection.queryReadBookMode(new CRPReadBookModeCallback() {
                    @Override
                    public void onReadBookMode(CRPReadBookMode mode) {
                        Log.d(TAG, "onReadBookMode: " + mode);
                    }
                });
                break;
            case R.id.btn_send_read_book_mode:
                bleConnection.sendReadBookMode(CRPReadBookMode.PAGE_UP_DOWN);
                break;
            case R.id.btn_send_heart_rate_alert:
                bleConnection.sendHeartRateAlert(true, (byte) 145);
                break;
            case R.id.btn_query_heart_rate_alert:
                bleConnection.queryHeartRateAlert(new CRPHeartRateAlertCallback() {
                    @Override
                    public void onHeartRateAlert(boolean enable, int hr) {
                        Log.d(TAG, "onHeartRateAlert: " + enable + ", " + hr);
                    }
                });
                break;
            case R.id.btn_query_firmware:
                bleConnection.queryFirmwareVersion(new CRPFirmwareVersionCallback() {
                    @Override
                    public void onVersion(String version) {
                        Log.d(TAG, "onVersion: " + version);
                        firmwareVersion = version;
                        updateTextView(tvFirmwareVersion, version);
                    }
                });

                bleConnection.queryFirmwareHash(new CRPFirmwareHashCallback() {
                    @Override
                    public void onHash(String hash) {
                        Log.d(TAG, "onHash: " + hash);
                    }
                });
                break;
            case R.id.btn_check_firmware:
                if (!TextUtils.isEmpty(firmwareVersion)) {
                    bleConnection.checkFirmwareVersion(
                            new CRPNewFirmwareVersionCallback() {
                                @Override
                                public void onNewVersion(CRPFirmwareVersionInfo info) {
                                    String version = info.getVersion();
                                    updateTextView(tvNewFirmwareVersion, version);
                                    isUpgrade = true;
                                }

                                @Override
                                public void onLatestVersion() {
                                    Log.d(TAG, "onLatestVersion");
                                    isUpgrade = false;
                                }
                            },
                            firmwareVersion,
                            CRPFirmwareCheckType.NORMAL);
                }
                break;
            case R.id.btn_firmware_upgrade:
                if (isUpgrade) {
                    bleConnection.startOta(CRPOtaMcu.PLATFORM_GOODIX, otaListener);
                }
                break;
            case R.id.btn_query_battery:
                bleConnection.setBatteryListener(new CRPBatteryListener() {
                    @Override
                    public void onBattery(int battery) {
                        updateTextView(tvBattery, battery + "%");
                    }

                    @Override
                    public void onRealTimeBattery(int battery, int mv) {
                        Log.d(TAG, "onRealTimeBattery: " + battery);
                    }
                });
                bleConnection.queryBattery();

                bleConnection.queryRealTimeBattery();
                break;
            case R.id.btn_sync_time:
                bleConnection.syncTime();
                break;
            case R.id.btn_send_binding_reminder:
                bleConnection.sendBindingReminder();
                break;
            case R.id.btn_send_user_info:
                CRPUserInfo userInfo = new CRPUserInfo(
                        75, 78, CRPUserInfo.MALE, 24, 65);
                bleConnection.sendUserInfo(userInfo);
                break;
            case R.id.btn_sync_step:
                bleConnection.queryCurrentSteps();
                bleConnection.queryHistoryStepsDetails(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_sync_history_step:
                bleConnection.queryHistorySteps(CRPHistoryDay.TODAY);
                bleConnection.queryHistoryStepsDetails(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_sync_sleep:
                bleConnection.queryHistorySleep(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_sync_history_sleep:
                bleConnection.queryHistorySleep(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_start_training:
                CRPTrainingGoalsInfo goalsInfo = new CRPTrainingGoalsInfo(CRPGoalsType.NOT_GOALS, 0);
                bleConnection.startTraining((byte) 2, goalsInfo);
                break;
            case R.id.btn_send_training_state:
                CRPTrainingGoalsInfo goalsInfo1 = new CRPTrainingGoalsInfo(CRPGoalsType.DISTANCE, 3000);
                bleConnection.sendTrainingState(CRPTrainingState.END, goalsInfo1);
                break;
            case R.id.btn_query_training_state:
                bleConnection.queryTrainingState();
                break;
            case R.id.btn_send_goals:
                bleConnection.sendDailyGoals(new CRPDailyGoalsInfo(6000, 400, 30, 5000));
                bleConnection.sendTrainingDayGoals(new CRPTrainingDayGoalsInfo(true, (byte) 1, 6000, 400, 30, 5000));
                break;
            case R.id.btn_query_goals:
                bleConnection.queryDailyGoals();
                bleConnection.queryTrainingDayGoals();
                break;
            case R.id.btn_query_support_message_list:
                bleConnection.querySupportMessageList(new CRPMessageCallback() {
                    @Override
                    public void onSupportMessageList(byte[] messageArray) {
                        Log.d(TAG, "onSupportMessageList: " + Arrays.toString(messageArray));
                    }
                });
                break;
            case R.id.btn_send_message:
                bleConnection.sendMessage((byte) CRPBleMessageType.MESSAGE_PHONE);
                break;
            case R.id.btn_query_remote_control_details:
                bleConnection.setRemoteControlDetailsListener(new CRPRemoteControlDetailsListener() {
                    @Override
                    public void onRemoteControlDetails(int mode, boolean ebable, CRPRemoteControlType type) {
                        Log.d(TAG, "onRemoteControlDetails: " + mode + ", " + ebable + ", " + type);
                    }

                });

                bleConnection.queryRemoteControlDetails();
                break;
            case R.id.btn_query_remote_control_state:
                bleConnection.sendRemoteControlState(true, new CRPRemoteControlStateCallback() {
                    @Override
                    public void onSendSuccess() {
                        Log.d(TAG, "onSendSuccess");
                    }
                });
                break;
            case R.id.btn_send_device_language:
                bleConnection.sendRemoteControlType(CRPRemoteControlType.PPT);
                break;
            case R.id.btn_query_history_sleep_list:
                bleConnection.queryHistorySleepList();
                break;
            case R.id.btn_query_sleep_info:
                bleConnection.querySleepInfo(28);
                break;
            case R.id.btn_query_sleep_details:
                bleConnection.querySleepDetails(28);
                break;
            case R.id.btn_query_sleep_chronotype:
                bleConnection.querySleepChronotype();
                break;
            case R.id.btn_end_sleep:
                bleConnection.sendSleepEnd();
                break;
            case R.id.btn_send_activity_reminder:
                bleConnection.sendActivityReminder(new CRPActivityReminderInfo(true, (byte) 40, (byte) 100, (byte) 9, (byte) 23));
                break;
            case R.id.btn_query_activity_reminder:
                bleConnection.queryActivityReminder();
                break;
            case R.id.btn_start_measure_heart_rate:
                bleConnection.startMeasureHeartRate();
                break;
            case R.id.btn_stop_measure_heart_rate:
                bleConnection.stopMeasureHeartRate();
                break;
            case R.id.btn_enable_timing_heart_rate:
                bleConnection.enableTimingHeartRate(2);
                bleConnection.queryTimingHeartRateState();
                break;
            case R.id.btn_disable_timing_heart_rate:
                bleConnection.disableTimingHeartRate();
                bleConnection.queryTimingHeartRateState();
                break;
            case R.id.btn_query_history_hreat_rate:
                bleConnection.queryHistoryHeartRate();
                break;
            case R.id.btn_query_timing_hreat_rate:
                bleConnection.queryHistoryTimingHeartRate(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_query_support_training_list:
                bleConnection.querySupportTraining();
                break;
            case R.id.btn_query_history_training:
                bleConnection.queryHistoryTraining();
                break;
            case R.id.btn_query_setting_info:
                bleConnection.querySettingInfo(new CRPSettingCallback() {
                    @Override
                    public void onSetting(CRPSettingInfo info) {
                        Log.d(TAG, "onSetting: " + info);
                    }
                });
                break;
            case R.id.btn_start_measure_blood_pressure:
                bleConnection.startMeasureBloodPressure();
                break;
            case R.id.btn_stop_measure_blood_pressure:
                bleConnection.stopMeasureBloodPressure();
                break;
            case R.id.btn_send_screen_resolution:
                DisplayMetrics displayMetrics = new DisplayMetrics();
                ((android.view.WindowManager) getSystemService(Context.WINDOW_SERVICE))
                        .getDefaultDisplay().getMetrics(displayMetrics);

                int width = displayMetrics.widthPixels;
                int height = displayMetrics.heightPixels;
                bleConnection.sendScreenResolution(width, height);
                break;
            case R.id.btn_query_history_voltage:
                bleConnection.queryHistoryVoltage(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_start_measure_blood_oxygen:
                bleConnection.startMeasureBloodOxygen();
                break;
            case R.id.btn_stop_measure_blood_oxygen:
                bleConnection.stopMeasureBloodOxygen();
                break;
            case R.id.btn_enable_shutter:
                bleConnection.enabelShutter(true);
                break;
            case R.id.btn_query_shutter_state:
                bleConnection.setShutterListener(new CRPShutterListener() {
                    @Override
                    public void onShutterState(boolean enable) {
                        Log.d(TAG, "onShutterState: " + enable);
                    }

                    @Override
                    public void onShutter() {
                        Log.d(TAG, "onShutter");
                    }
                });
                bleConnection.queryShutterState();
                break;
            case R.id.btn_send_rfpower:
                bleConnection.sendRFPower(CRPRFPower.HIGH);
                break;
            case R.id.btn_query_rfpower:
                bleConnection.queryRFPower(new CRPRFPowerCallback() {
                    @Override
                    public void onPower(CRPRFPower power) {
                        Log.d(TAG, "onPower: " + power);
                    }
                });
                break;
            case R.id.shutdown:
                bleConnection.shutDown(new CRPShutDownCallback() {
                    @Override
                    public void onSuccess() {
                        Log.d(TAG, "onSuccess");
                    }
                });
                break;
            case R.id.reset:
                bleConnection.reset();
                break;
            case R.id.btn_restart:
                bleConnection.restart();
                break;
            case R.id.btn_query_action_details:
                bleConnection.queryActionDetails(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_enable_timing_hrv:
                bleConnection.enableTimingHrv(15);
                bleConnection.queryTimingHrvState();
                break;
            case R.id.btn_disable_timing_hrv:
                bleConnection.disableTimingHrv();
                bleConnection.queryTimingHrvState();
                break;
            case R.id.btn_start_measure_hrv:
                bleConnection.startMeasureHrv();
                break;
            case R.id.btn_stop_measure_hrv:
                bleConnection.stopMeasureHrv();
                break;
            case R.id.btn_query_hrv_measure_result:
                bleConnection.queryHistoryHrv();
                bleConnection.queryHistoryTimingHrv(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_enable_timing_blood_oxygen:
                bleConnection.enableTimingBloodOxygen(4);
                bleConnection.queryTimingBloodOxygenState();
                break;
            case R.id.btn_disable_timing_blood_oxygen:
                bleConnection.disableTimingBloodOxygen();
                bleConnection.queryTimingBloodOxygenState();
                break;
            case R.id.btn_query_continue_blood_oxygen:
                bleConnection.queryHistoryBloodOxygen();
                bleConnection.queryHistoryTimingBloodOxygen(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_enable_timing_temp:
                bleConnection.enableTimingTemp();
                break;
            case R.id.btn_disable_timing_temp:
                bleConnection.disableTimingTemp();
                break;
            case R.id.btn_query_timing_temp_state:
                bleConnection.queryTimingTempState();
                break;
            case R.id.btn_query_timing_temp:
                bleConnection.queryHistoryTemp(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_start_measure_stress:
                bleConnection.startMeasureStress();
                break;
            case R.id.btn_stop_measure_stress:
                bleConnection.stopMeasureStress();
                break;
            case R.id.btn_query_history_stress:
                bleConnection.queryHistoryStress();
                bleConnection.queryHistoryTimingStress(CRPHistoryDay.TODAY);
                break;
            case R.id.btn_enable_sos:
                bleConnection.enableSos(true);
                break;
            case R.id.btn_query_sos_state:
                bleConnection.querySosState(new CRPSosStateCallback() {
                    @Override
                    public void onSosState(boolean enable) {
                        Log.d(TAG, "onSosState: " + enable);
                    }
                });
                break;
            case R.id.btn_send_auto_lock:
                bleConnection.sendAutoLock((byte) 10);
                break;
            case R.id.btn_query_auto_lock:
                bleConnection.queryAutoLock();
                break;
            case R.id.btn_send_brightness:
                bleConnection.sendBrightness((byte) 10);
                break;
            case R.id.btn_query_brightness:
                bleConnection.queryBrightness();
                break;
            case R.id.btn_query_support_display_feature:
                bleConnection.querySupportDisplayFeature();
                break;
            case R.id.btn_send_display_feature:
                List<CRPDisplayFeature> displayFeatureList = new ArrayList<>();
                displayFeatureList.add(CRPDisplayFeature.FEATURE_TIME);
                displayFeatureList.add(CRPDisplayFeature.FEATURE_HR);
                displayFeatureList.add(CRPDisplayFeature.FEATURE_CALORIES);
                displayFeatureList.add(CRPDisplayFeature.FEATURE_STEPS);
                bleConnection.sendDisplayFeature(displayFeatureList);
                break;
            case R.id.btn_query_display_feature:
                bleConnection.queryDisplayFeature();
                break;
            case R.id.btn_query_exercise_details:
                queryAndReportExerciseDetails();
                break;
            default:
                break;
        }
    }

    /**
     * 查询锻炼详情并上报给API
     */
    private void queryAndReportExerciseDetails() {
        if (bleConnection == null) {
            Log.e(TAG, "BLE connection is null");
            return;
        }
        
        // 查询历史训练数据
        bleConnection.queryHistoryTraining();
        
        // 查询今日训练数据
        bleConnection.queryHistoryDailyTraining(CRPHistoryDay.TODAY);
        
        Log.d(TAG, "Querying exercise details...");
        showToast("正在查询锻炼详情...");
    }
    
    /**
     * 处理训练数据并上报给API
     */
    private void processAndReportTrainingData(CRPTrainingInfo trainingInfo) {
        if (trainingInfo == null) {
            Log.w(TAG, "Training info is null");
            return;
        }
        
        try {
            // 获取设备SN
            String deviceSn = bleDevice != null ? bleDevice.getAddress() : "unknown";
            
            // 构建锻炼详情数据
            String exerciseType = String.valueOf(trainingInfo.getTrainingType());
            String startDate = formatTimestamp(trainingInfo.getStartTime());
            String endDate = formatTimestamp(trainingInfo.getEndTime());
            int exerciseTime = trainingInfo.getDuration(); // 锻炼时长（秒）
            int exerciseCalorie = trainingInfo.getCalories(); // 消耗卡路里
            String recordDate = getCurrentDate();
            
            Log.d(TAG, "Exercise Details - Type: " + exerciseType + 
                  ", Start: " + startDate + 
                  ", End: " + endDate + 
                  ", Duration: " + exerciseTime + 
                  ", Calories: " + exerciseCalorie);
            
            // 这里可以调用API上报数据
            // 示例：调用Flutter端的方法通过MethodChannel上报数据
            reportExerciseDetailsToFlutter(deviceSn, exerciseType, startDate, endDate, 
                                         exerciseTime, exerciseCalorie, recordDate);
            
        } catch (Exception e) {
            Log.e(TAG, "Error processing training data", e);
        }
    }
    
    /**
     * 处理每日训练数据并上报给API
     */
    private void processAndReportDailyTrainingData(CRPDailyTrainingInfo dailyTrainingInfo) {
        if (dailyTrainingInfo == null) {
            Log.w(TAG, "Daily training info is null");
            return;
        }
        
        try {
            // 获取设备SN
            String deviceSn = bleDevice != null ? bleDevice.getAddress() : "unknown";
            
            // 构建锻炼详情数据
            String exerciseType = "daily_summary"; // 每日汇总类型
            String recordDate = getCurrentDate();
            int exerciseTime = dailyTrainingInfo.getDuration(); // 总锻炼时长
            int exerciseCalorie = dailyTrainingInfo.getCalories(); // 总消耗卡路里
            
            Log.d(TAG, "Daily Exercise Summary - Duration: " + exerciseTime + 
                  ", Calories: " + exerciseCalorie);
            
            // 上报每日汇总数据
            reportExerciseDetailsToFlutter(deviceSn, exerciseType, recordDate, recordDate, 
                                         exerciseTime, exerciseCalorie, recordDate);
            
        } catch (Exception e) {
            Log.e(TAG, "Error processing daily training data", e);
        }
    }
    
    /**
     * 通过MethodChannel将锻炼详情上报给Flutter端
     */
    private void reportExerciseDetailsToFlutter(String deviceSn, String exerciseType, 
                                              String startDate, String endDate, 
                                              int exerciseTime, int exerciseCalorie, 
                                              String recordDate) {
        // 这里需要实现MethodChannel调用
        // 由于这是示例代码，这里只是打印日志
        Log.d(TAG, "Reporting exercise details to Flutter:");
        Log.d(TAG, "DeviceSn: " + deviceSn);
        Log.d(TAG, "ExerciseType: " + exerciseType);
        Log.d(TAG, "StartDate: " + startDate);
        Log.d(TAG, "EndDate: " + endDate);
        Log.d(TAG, "ExerciseTime: " + exerciseTime);
        Log.d(TAG, "ExerciseCalorie: " + exerciseCalorie);
        Log.d(TAG, "RecordDate: " + recordDate);
        
        showToast("锻炼详情已获取，准备上报");
    }
    
    /**
     * 格式化时间戳为日期字符串
     */
    private String formatTimestamp(long timestamp) {
        if (timestamp <= 0) {
            return getCurrentDate();
        }
        
        try {
            java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format(new java.util.Date(timestamp * 1000L)); // 假设时间戳是秒
        } catch (Exception e) {
            Log.e(TAG, "Error formatting timestamp", e);
            return getCurrentDate();
        }
    }
    
    /**
     * 获取当前日期字符串
     */
    private String getCurrentDate() {
        java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new java.util.Date());
    }

    CRPDisplayListener displayListener = new CRPDisplayListener() {
        @Override
        public void onAutoLock(int seconds) {
            Log.d(TAG, "onAutoLock: " + seconds);
        }

        @Override
        public void onBrightness(int brightness) {
            Log.d(TAG, "onBrightness: " + brightness);
        }

        @Override
        public void onSupportDisplayFeature(List<CRPDisplayFeature> list) {
            Log.d(TAG, "onSupportDisplayFeature: " + list);
        }

        @Override
        public void onDisplayFeature(List<CRPDisplayFeature> list) {
            Log.d(TAG, "onDisplayFeature: " + list);
        }
    };

    CRPDeviceVoltageListener voltageListener = new CRPDeviceVoltageListener() {
        @Override
        public void onHistoryVoltage(CRPVoltageInfo info) {
            Log.d(TAG, "onHistoryVoltage: " + info);
        }
    };

    CRPActivityReminderListener activityReminderListener = new CRPActivityReminderListener() {
        @Override
        public void onActivityReminder() {

        }

        @Override
        public void onActivityReminderDetails(CRPActivityReminderInfo info) {
            Log.d(TAG, "onSedentaryReminderPeriod: " + info);
        }
    };

    private CRPGoalsListener goalsListener = new CRPGoalsListener() {
        @Override
        public void onGoalsAchieved(CRPGoalsType type) {
            Log.d(TAG, "onGoalAchieved: " + type);
        }

        @Override
        public void onDailyGoals(CRPDailyGoalsInfo info) {
            Log.d(TAG, "onDailyGoals: " + info);
        }

        @Override
        public void onTrainingDayGoals(CRPTrainingDayGoalsInfo info) {
            Log.d(TAG, "onTrainingDayGoals: " + info);
        }
    };

    private CRPActionDetailsListener actionDetailsListener = new CRPActionDetailsListener() {
        @Override
        public void onActionDetails(CRPActionDetailsInfo info) {
            Log.d(TAG, "onActionDetails: " + info.getHistoryDay());

            // 分段打印 actionList 数据
            List<Integer> actionList = info.getActionList();
            if (actionList != null && !actionList.isEmpty()) {
                StringBuilder sb = new StringBuilder();
                sb.append("ActionList size: ").append(actionList.size()).append("\n");

                // 每次打印100个元素
                int chunkSize = 100;
                for (int i = 0; i < actionList.size(); i += chunkSize) {
                    int end = Math.min(i + chunkSize, actionList.size());
                    List<Integer> subList = actionList.subList(i, end);
                    Log.d(TAG, "ActionList[" + i + "-" + (end-1) + "]: " + subList);
                }
            }
        }
    };

    private CRPTrainingChangeListener trainingChangeListener = new CRPTrainingChangeListener() {
        @Override
        public void onTrainingState(CRPTrainingState state) {
            Log.d(TAG, "onTrainingState: " + state);
        }

        @Override
        public void onTrainingState(int trainingType, CRPTrainingState state) {
            Log.d(TAG, "onTrainingState: " + trainingType + ", " + state);
        }

        @Override
        public void onGoalsReached(CRPGoalsType type) {
            Log.d(TAG, "onGoalsReached: " + type);
        }

        @Override
        public void onSupportTrainingList(List<Integer> list) {
            Log.d(TAG, "onSupportTrainingList: " + list.toString());
        }

        @Override
        public void onHistoryTrainingChange(List<CRPHistoryTrainingInfo> list) {
            if (list == null || list.isEmpty()) {
                return;
            }
            Log.d(TAG, "onHistoryTrainingChange: " + list);

            bleConnection.queryTraining(0);
        }

        @Override
        public void onTrainingChange(CRPTrainingInfo info) {
            Log.d(TAG, "onTrainingChange: " + info.toString());
            // 处理并上报训练数据
            processAndReportTrainingData(info);
        }

        @Override
        public void onHistoryDailyTrainingChange(List<Long> list) {
            Log.d(TAG, "onHistoryDailyTrainingChange: " + list.toString());
        }

        @Override
        public void onDailyTrainingChange(CRPDailyTrainingInfo info) {
            Log.d(TAG, "onDailyTrainingChange: " + info.toString());
            // 处理并上报每日训练数据
            processAndReportDailyTrainingData(info);
        }
    };

    private void showToast(String nsg) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(DeviceActivity.this, nsg, Toast.LENGTH_LONG).show();
            }
        });
    }

    private CRPHrvChangeListener hrvChangeListener = new CRPHrvChangeListener() {

        @Override
        public void onHrv(int hrv) {
            Log.d(TAG, "onHrv: " + hrv);
        }

        @Override
        public void onHistoryHrv(List<CRPHistoryHrvInfo> list) {
            for (CRPHistoryHrvInfo info : list) {
                Log.d(TAG, "onHistoryHrv: " + info);
            }
        }

        @Override
        public void onTimingInterval(int interval) {
            Log.d(TAG, "onMeasureInterval: " + interval);
        }

        @Override
        public void onTimingHrv(CRPTimingHrvInfo info) {
            Log.d(TAG, "onTimingHrv: " + info);
        }

    };

    private CRPTempChangeListener tempChangeListener = new CRPTempChangeListener() {
        @Override
        public void onTimingState(CRPTempType type, int interval) {
            Log.d(TAG, "onTimingState: " + type + ", interval=" + interval);
        }

        @Override
        public void onHistoryTempChange(CRPHistoryTempInfo info) {
            Log.d(TAG, "onHistoryTempChange: " + info);
        }

        // 新增方法：实现 onMeasureComplete
        public void onMeasureComplete(float temperature) {
            Log.d(TAG, "onMeasureComplete: " + temperature);
        }
    };


    private CRPStressChangeListener stressChangeListener = new CRPStressChangeListener() {
        @Override
        public void onStressChange(int stress) {
            Log.d(TAG, "=== REALTIME Stress Change ===");
            Log.d(TAG, "Stress value: " + stress);
            Log.d(TAG, "=== END REALTIME Stress Change ===");
        }

        @Override
        public void onHistoryStressChange(List<CRPHistoryStressInfo> list) {
            Log.d(TAG, "onHistoryStressChange list: " + list);
        }

        @Override
        public void onTimingInterval(int interval) {
            Log.d(TAG, "onTimingInterval: " + interval);
        }

        public void onTimingStress(CRPTimingStressInfo info) {
            Log.d(TAG, "onTimingStress: " + info);
            // 示例：逐条打印全天压力条目
            try {
                if (info != null && info.getList() != null) {
                    List<Integer> values = info.getList();
                    for (int i = 0; i < values.size(); i++) {
                        Log.d(TAG, "Stress[" + i + "]=" + values.get(i));
                    }
                }
            } catch (Throwable t) {
                Log.w(TAG, "print timing stress failed", t);
            }
        }
    };



    CRPStepsChangeListener stepsChangeListener = new CRPStepsChangeListener() {
        @Override
        public void onCurrentSteps(CRPStepsInfo info) {
            Log.d(TAG, "onStepChange: " + info.toString());
            updateStepInfo(info.getSteps(), info.getDistance(), info.getCalories());
            showToast(info.toString());
        }

        @Override
        public void onHistorySteps(CRPHistoryDay historyDay, CRPStepsInfo info) {
            Log.d(TAG, "onPastStepChange: " + historyDay.getValue() + " - " + info.toString());
        }

        @Override
        public void onHistoryStepsDetails(CRPStepsDetailsInfo info) {
            Log.d(TAG, "onHistoryStepsDetails: " + info);
        }

    };

    CRPSleepChangeListener sleepChangeListener = new CRPSleepChangeListener() {

        @Override
        public void onHistorySleepChange(CRPHistoryDay historyDay, CRPSleepInfo info) {
            Log.d(TAG, "onPastSleepChange: " + historyDay.getValue() + " - " + info.toString());
        }

        @Override
        public void onHistorySleepListChange(List<com.crrepa.ble.conn.bean.CRPHistorySleepTimeInfo> list) {
            Log.d(TAG, "onHistorySleepListChange: " + list);
        }

        @Override
        public void onSleepDetails(CRPSleepDetailsInfo info) {
            Log.d(TAG, "onSleepDetails: " + info);
        }

        @Override
        public void onSleepInfo(CRPSleepInfo info) {
            Log.d(TAG, "onSleepInfo: " + info);
        }

        @Override
        public void onSleepChronotype(CRPSleepChronotypeInfo info) {
            Log.d(TAG, "onSleepChronotype: " + info);
        }

        @Override
        public void onSleepEnd(boolean success) {
            Log.d(TAG, "onSleepEnd: " + success);
        }
    };

    CRPHeartRateChangeListener heartRateChangeListener = new CRPHeartRateChangeListener() {
        @Override
        public void onTimingInterval(int interval) {
            Log.d(TAG, "onTimingInterval: " + interval);
        }

        @Override
        public void onRealtimeHeartRate(int hr) {
            Log.d(TAG, "onMeasuring: " + hr);
            updateTextView(tvHeartRate, String.format(getString(R.string.heart_rate), hr));
        }

        @Override
        public void onHeartRate(int hr) {
            Log.d(TAG, "onHeartRate: " + hr);
        }

        @Override
        public void onHistoryHeartRate(List<CRPHistoryHeartRateInfo> list) {
            for (CRPHistoryHeartRateInfo info : list) {
                Log.d(TAG, "onHistoryHeartRate: " + info);
            }
        }

        @Override
        public void onTimingHeartRate(CRPHeartRateInfo info) {
            Log.d(TAG, "on24HourMeasureResult: " + info.toString());
        }

    };

    private CRPBloodPressureChangeListener bloodPressureChangeListener = new CRPBloodPressureChangeListener() {
        @Override
        public void onBloodPressureChange(int sbp, int dbp) {
            Log.d(TAG, "onBloodPressureChange: " + sbp + ", " + dbp);
        }
    };

    CRPBloodOxygenChangeListener bloodOxygenChangeListener = new CRPBloodOxygenChangeListener() {

        @Override
        public void onTimingInterval(int interval) {
            Log.d(TAG, "onTimingMeasure: " + interval);
        }

        @Override
        public void onBloodOxygen(int bloodOxygen) {
            updateTextView(tvBloodOxygen,
                    String.format(getString(R.string.blood_oxygen), bloodOxygen));
        }

        @Override
        public void onHistoryBloodOxygen(List<CRPHistoryBloodOxygenInfo> list) {
            for (CRPHistoryBloodOxygenInfo info : list) {
                Log.d(TAG, "onHistoryBloodOxygen: " + info.toString());
            }
        }

        @Override
        public void onTimingBloodOxygen(CRPTimingBloodOxygenInfo info) {
            Log.d(TAG, "onTimingBloodOxygen: " + info);
            bleConnection.queryHistoryTimingBloodOxygen(info.getHistoryDay().nextDay());
        }

        @Override
        public void onSupportBloodOxygenType(CRPBloodOxygenType type) {
            Log.d(TAG, "onSupportBloodOxygenType: " + type);
        }
    };


    CRPOtaListener otaListener = new CRPOtaListener() {
        @Override
        public void onDownloadStarting() {
            Log.d(TAG, "onFirmwareDownloadStarting");
            updateTextView(tvUpgradeState, getString(R.string.dfu_status_download_starting));
        }

        @Override
        public void onDownloadComplete() {
            Log.d(TAG, "onFirmwareDownloadComplete");
            updateTextView(tvUpgradeState, getString(R.string.dfu_status_download_complete));
        }

        @Override
        public void onBootloadStarting() {
            Log.d(TAG, "onBootloadStarting");
        }

        @Override
        public void onBootloadComplete() {
            Log.d(TAG, "onBootloadComplete");
        }

        @Override
        public void onProgressStarting() {
            Log.d(TAG, "onUpgradeProgressStarting");
            updateTextView(tvUpgradeState, getString(R.string.dfu_status_starting));
        }

        @Override
        public void onProgressChanged(int percent, float speed) {
            Log.d(TAG, "onUpgradeProgressChanged: " + percent);
            String status = String.format(getString(R.string.dfu_status_uploading_part), percent);
            updateTextView(tvUpgradeState, status);
        }

        @Override
        public void onCompleted() {
            Log.d(TAG, "onUpgradeCompleted");
            updateTextView(tvUpgradeState, getString(R.string.dfu_status_completed));
            isUpgrade = true;
        }

        @Override
        public void onAborted() {
            Log.d(TAG, "onUpgradeAborted");
            updateTextView(tvUpgradeState, getString(R.string.dfu_status_aborted));
        }

        @Override
        public void onError(int errorType, String message) {
            Log.d(TAG, "onError: " + errorType);
            updateTextView(tvUpgradeState, message);
//            mBleConnection.abortFirmwareUpgrade();
        }
    };


    void updateStepInfo(int step, int distance, int calories) {
        updateTextView(tvStep, String.format(getString(R.string.steps), step));
        updateTextView(tvDistance, String.format(getString(R.string.distance), distance));
        updateTextView(tvCalorie, String.format(getString(R.string.calorie), calories));
    }

    void updateSleepInfo(int restful, int light) {
        updateTextView(tvRestful, String.format(getString(R.string.restful), restful));
        updateTextView(tvLight, String.format(getString(R.string.light), light));
    }

    void updateConnectState(final int state) {
        if (state < 0) {
            return;
        }
        updateTextView(tvConnectState, getString(state));
    }

    void updateTextView(final TextView view, final String con) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                view.setText(con);
            }
        });
    }

}
